﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows;
using System.Reflection;
using GTServices.WPF.Client.Extensions;
using GTServices.WPF.Client.Interfaces;
using GTServices.Model;
using GTServices.Entities;
using GTServices.WPF.Client.CoRoutines;
using GTServices.WPF.Client.ViewModels.Entities;
using Caliburn.Micro;
using GTServices.Model.CoRoutine;


using System.ComponentModel;


namespace GTServices.WPF.Client.ViewModels
{
    public class ManageViewModel : Screen
    {
        public ListCollectionView Categories { get; set; }
        public ListCollectionView Patterns { get; set; }
        public ListCollectionView Languages { get; set; }
        public ListCollectionView FileExtensions { get; set; }
        public ListCollectionView Templates { get; set; }
        public ListCollectionView Classifications { get; set; }

        private PropertyChangedBase _selectedViewModel;
        public PropertyChangedBase SelectedViewModel { get { return _selectedViewModel; }
            set
            {
                _selectedViewModel = value;
                NotifyOfPropertyChange(() => SelectedViewModel); 
            }
        }

        public BindableCollection<IEntityViewModel> SelectedItems { get; set; } 


        public ManageViewModel()
        {
            Init();
            this.SelectedItems = new BindableCollection<IEntityViewModel>(); 
        }

        public void Init()
        {
            Categories = new ListCollectionView(ModelViewModels.Instance.CategoryViewModels);
            Patterns = new ListCollectionView(ModelViewModels.Instance.PatternViewModels);
            Languages = new ListCollectionView(ModelViewModels.Instance.LanguageViewModels);
            FileExtensions = new ListCollectionView(ModelViewModels.Instance.FileExtensionViewModels);
            Templates = new ListCollectionView(ModelViewModels.Instance.TemplateViewModels);
            Classifications = new ListCollectionView(ModelViewModels.Instance.ClassficationViewModels);

        }

        public void ExportSelectedItems()
        {
            if (this.SelectedItems.Count < 1)
                return;

            EntityCollection ec = new EntityCollection();
            foreach(BaseEntity be in this.SelectedItems.Select(x=> x.Model)){
                 ec.Entities.Add(be as BaseEntity);
            }
         
            Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
            sfd.DefaultExt = "*.xml";
            sfd.Filter = "Xml documents (.xml)|*.xml"; // Filter files by extension 
            if (sfd.ShowDialog() == true)
            {
                try
                {
                    using (System.IO.StreamWriter sw = new System.IO.StreamWriter(System.IO.File.Open(sfd.FileName, System.IO.FileMode.Create)))
                    {
                        sw.Write(GTApplication.Instance.DataModel.GetEntityAsXml(ec));
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
        }
        public void RemoveSelectedItems()
        {
            if(this.SelectedItems.Count < 1)
                return; 

            var list = GTApplication.Instance.DataModel.GetListFor(this.SelectedItems[0].Model.GetType());
            if (list != null)
            {
                foreach (IEntityViewModel evm in this.SelectedItems.ToList())
                {
                    list.Remove(evm.Model);
                }
            }
        }
        public void Add(String type)
        {
            Object item = GTApplication.Instance.DataModel.Create(type);

            if (item != null)
            {
                if (!GTApplication.Instance.DataModel.TryAddItemToList(item))
                {
                    //TODO Error/Log
                    return;
                }
                //TODO: Log success
                PropertyChangedBase pcb = ModelViewModels.Instance.TryGetViewModelFrom(item);
            }
            else
            {
                //TODO: Log/Notify
            }
        }
        /// <summary>
        /// This probably isn't the best way to handle this. 
        /// </summary>
        /// <param name="context"></param>
        public void TabControlSelectionChanged(ActionExecutionContext context)
        {
            //Need to get access to the control that fired the event. 
            SelectionChangedEventArgs eventArgs = context.EventArgs as SelectionChangedEventArgs;

            if (eventArgs != null && eventArgs.AddedItems.Count > 0 )
            {
                TabItem ti = eventArgs.AddedItems[0] as TabItem;
                if (ti != null)
                {
                    ListView lv = ti.Content as ListView;
                    if (lv != null)
                    {
                        //Now we can clear the selected Items. 
                        lv.SelectedItems.Clear(); 
                    }
                }
            }else{
                int i = 0;
            }
        }

        public void SelectedItemChanged(ActionExecutionContext context, String itemType)
        {
            SelectionChangedEventArgs eventArgs = context.EventArgs as SelectionChangedEventArgs;
            ListView lv = context.Source as ListView;
            if (lv != null)
            {
                this.SelectedItems.Clear();

                foreach (IEntityViewModel iev in lv.SelectedItems)
                {
                    if (iev.Model.GetType().Name == itemType)
                    {
                        this.SelectedItems.Add(iev);
                    }
                }

                //Now we have to generate a view model. 
                if (this.SelectedItems.Count > 1)
                {
                    GenerateMultiselectViewModel(itemType);
                }
                else if (this.SelectedItems.Count == 1)
                {
                    this.SelectedViewModel = this.SelectedItems[0] as PropertyChangedBase;
                }
            }
            //Need to mark these as handled to prevent the event from propagating. 
            eventArgs.Handled = true;
        }

        private void GenerateMultiselectViewModel(string itemType)
        {
            if (this.SelectedItems.Count < 1)
                return;

            Type viewModelType = this.SelectedItems[0].GetType();
            Type modelType = this.SelectedItems[0].Model.GetType();

            IEntityViewModel viewModel = (IEntityViewModel)Activator.CreateInstance(viewModelType);
            Object model = Activator.CreateInstance(modelType);

            viewModel.Model = model;

            //Sync the selected items models to the temporary ViewModel's model.
            SyncManyModelItemsToModel(viewModel, this.SelectedItems.ToList());
          
            //Hook the ViewModel's property changed event. This will let us propagate our changes to the other viewModels. 
            (viewModel as PropertyChangedBase).PropertyChanged += (x, y) =>
            {
                int i = 0;
                PropertyInfo pi = x.GetType().GetProperty(y.PropertyName);
                if (pi != null)
                {
                    object value = pi.GetValue(x, null); 
                    foreach (IEntityViewModel evm in SelectedItems)
                    {
                        pi.SetValue(evm, value, null); 
                    }
                }
            };


            //Next we need to Sync the temporary model to the values of the 
            if (viewModel is PropertyChangedBase)
            {
                this.SelectedViewModel = viewModel as PropertyChangedBase;
            }
            else
            {
                //TODO: Log?? Should never get here. 
         
            }
        }
        public void ImportPatternsFromTxt()
        {

            var languages = ModelViewModels.Instance.LanguageViewModels.ToList();

            ListPickerViewModel lpvm = new ListPickerViewModel(languages.ToList<Object>(), "Language.Name", "Language.Name");


            if (GTWindowManager.Instance.ShowDialog(lpvm, 300, 300) == true && lpvm.SelectedItem != null)
            {
                Language language = (lpvm.SelectedItem as LanguageViewModel).Language;
                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();

                if (ofd.ShowDialog() == true)
                {
                    string file = ofd.FileName;
                    GTApplication.Instance.DataModel.LoadPatternsFromFile(file, language);
                }
            }
        }

        public void Save()
        {
            try
            {
                GTApplication.Instance.DataModel.SaveState();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
      
        public void ImportEntityXml()
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.DefaultExt = ".xml"; // Default file extension
            dlg.Filter = "Xml Documents (.xml)|*.xml"; // Filter files by extension 
            dlg.Multiselect = true;

            if (dlg.ShowDialog() == true)
            {

                ImportCommand ic = new ImportCommand(dlg.FileNames.ToList());

                ic.Completed += (x, y) =>
                {
                    if (ic.Success == true)
                    {
                        MessageBox.Show("Import successful");
                    }
                    else
                    {
                        MessageBox.Show("Import Failed");
                    }
                };

                StatusWindowViewModel statusWindow = new StatusWindowViewModel(ic, "Importing, Please Wait..");

                GTWindowManager.Instance.ShowWindow(statusWindow, 100, 300);

                Dispatcher.Instance.QueueItem(ic);
            }
        }

        private void SyncManyModelItemsToModel(IEntityViewModel viewModel, List<IEntityViewModel> items)
        {
            if(items.Count < 2){
                return;
            }

            foreach (PropertyInfo info in viewModel.Model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetField))
            {
                if(ReflectionUtilities.IsIListOfGenericType(info.PropertyType, typeof(BaseEntity)))
                    continue; //Skip for now. 

                object baseValue = info.GetValue(items[0].Model, null);
                bool allMatch = true;
                foreach (IEntityViewModel item in items)
                {
                   var compareTo = info.GetValue(item.Model, null);

                   if ( (compareTo != null && baseValue != null))
                   {
                       if (!baseValue.Equals(compareTo))
                       {
                           allMatch = false;
                           break;
                       }
                   }
                   else if(!(compareTo == null && baseValue == null)) //One or the other is equal to null.. so they are not equal.
                   {
                       allMatch = false;
                       break;
                   }
                   //then they both must be equal to null, therfore we can continue as they are equal. 
                }

                if (allMatch)
                {
                    info.SetValue(viewModel.Model, baseValue, null); 
                }else{
                    info.SetValue(viewModel.Model, null, null); 
                }
            }
        }
    }
}
